package main

import (
	"encoding/binary"
	"fmt"
	"github.com/gorilla/websocket"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"sync"
)

// WebSocket 升级器
var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true }, // 允许跨域
}

// 客户端管理器
type ClientManager struct {
	clients       map[*Client]bool
	register      chan *Client
	unregister    chan *Client
	broadcast     chan []byte
	ffmpegCmd     *exec.Cmd
	mutex         sync.Mutex
	ffmpegRunning bool // 添加FFmpeg运行状态标志
}

// 客户端连接
type Client struct {
	conn *websocket.Conn
	send chan []byte
}

// 全局客户端管理器
var manager = ClientManager{
	clients:       make(map[*Client]bool),
	register:      make(chan *Client),
	unregister:    make(chan *Client),
	broadcast:     make(chan []byte),
	ffmpegRunning: false, // 初始化FFmpeg状态
}

func main() {
	// 启动客户端管理器协程
	go manager.start()
	// 注册HTTP处理函数
	http.HandleFunc("/page", serveWebPage) // 提供HTML页面
	http.HandleFunc("/ws/audio/", handleWebSocket)
	http.HandleFunc("/start", startFFmpeg)
	http.HandleFunc("/stop", stopFFmpeg)

	// 启动服务器
	log.Println("服务器启动，监听端口 :8089")
	log.Fatal(http.ListenAndServe(":8089", nil))
}

// 提供HTML页面
func serveWebPage(w http.ResponseWriter, r *http.Request) {
	// 设置内容类型
	w.Header().Set("Content-Type", "text/html; charset=utf-8")

	// 直接在代码中嵌入HTML内容
	fmt.Fprint(w, `<!DOCTYPE html>
<html>
<head>
    <title>WebSocket音频播放器</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; }
        button { padding: 10px 20px; font-size: 16px; margin-right: 10px; }
        .status { margin-top: 20px; padding: 10px; background-color: #f0f0f0; }
    </style>
</head>
<body>
    <h1>WebSocket音频播放器</h1>
    <button id="connectButton">连接</button>
    <button id="disconnectButton" disabled>断开</button>
    <div class="status" id="status">状态: 未连接</div>
    
    <script>
        const audioContext = new (window.AudioContext || window.webkitAudioContext)();
        let ws;
        let audioQueue = []; // 音频缓冲区
        let isPlaying = false;
        const statusElement = document.getElementById('status');
        
        document.getElementById('connectButton').addEventListener('click', connect);
        document.getElementById('disconnectButton').addEventListener('click', disconnect);
        
        function connect() {
            // 连接到WebSocket服务器
            ws = new WebSocket('ws://' + window.location.host + '/ws/audio/123456');
            
            ws.onopen = function() {
                console.log('WebSocket连接已建立');
                document.getElementById('connectButton').disabled = true;
                document.getElementById('disconnectButton').disabled = false;
                statusElement.textContent = '状态: 已连接，正在接收音频...';
            };
            
            ws.onmessage = function(event) {
                // 确保数据是ArrayBuffer类型
                let arrayBuffer;
                
                if (event.data instanceof ArrayBuffer) {
                    arrayBuffer = event.data;
                } else if (event.data instanceof Blob) {
                    // 如果是Blob类型，转换为ArrayBuffer
                    const reader = new FileReader();
                    reader.onload = function() {
                        processAudioData(reader.result);
                    };
                    reader.readAsArrayBuffer(event.data);
                    return; // 提前返回，等待FileReader完成
                } else {
                    console.error('收到未知类型的消息:', typeof event.data);
                    return;
                }
                
                // 处理音频数据
                processAudioData(arrayBuffer);
            };
            
            ws.onclose = function() {
                console.log('WebSocket连接已关闭');
                document.getElementById('connectButton').disabled = false;
                document.getElementById('disconnectButton').disabled = true;
                statusElement.textContent = '状态: 未连接';
                isPlaying = false;
            };
            
            ws.onerror = function(error) {
                console.error('WebSocket错误:', error);
                statusElement.textContent = '状态: 连接错误';
            };
        }
        
        function disconnect() {
            if (ws) {
                ws.close();
                ws = null;
            }
        }
        
        function playAudio() {
            if (audioQueue.length === 0) {
                isPlaying = false;
                return;
            }
            
            isPlaying = true;
            const audioData = audioQueue.shift();
            
            // 将ArrayBuffer转换为Float32Array（Web Audio API需要）
            const pcmData = new Int16Array(audioData);
            const floatData = new Float32Array(pcmData.length);
            
            for (let i = 0; i < pcmData.length; i++) {
                // 将16位整数转换为[-1, 1]范围内的浮点数
                floatData[i] = pcmData[i] / 32768.0;
            }
            
            // 创建音频缓冲区并播放
            const audioBuffer = audioContext.createBuffer(
                2,                  // 声道数
                floatData.length / 2, // 每声道样本数
                44100               // 采样率
            );
            
            // 填充左右声道数据
            const leftChannel = audioBuffer.getChannelData(0);
            const rightChannel = audioBuffer.getChannelData(1);
            
            for (let i = 0; i < floatData.length; i += 2) {
                leftChannel[i / 2] = floatData[i];
                rightChannel[i / 2] = floatData[i + 1];
            }
            
            // 创建并播放音频源
            const source = audioContext.createBufferSource();
            source.buffer = audioBuffer;
            source.connect(audioContext.destination);
            source.onended = playAudio; // 一个缓冲区播放完后继续播放下一个
            source.start();
        }
        
        function processAudioData(arrayBuffer) {
            // 解析帧头（前4字节是长度）
            const dataView = new DataView(arrayBuffer);
            const length = dataView.getUint32(0, false);
            const audioData = arrayBuffer.slice(4, 4 + length);
            
            // 将PCM数据加入缓冲区
            audioQueue.push(audioData);
            
            // 如果没有在播放，开始播放
            if (!isPlaying) {
                playAudio();
            }
        }
    </script>
</body>
</html>`)
}

// 处理WebSocket连接
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("WebSocket升级失败:", err)
		return
	}

	client := &Client{conn: conn, send: make(chan []byte, 256)}
	manager.register <- client

	// 启动读取和写入协程
	go client.read()
	go client.write()
}

// 客户端读取协程
func (c *Client) read() {
	defer func() {
		manager.unregister <- c
		c.conn.Close()
	}()

	for {
		// 客户端可能发送控制消息，但这里我们只处理音频数据发送
		_, _, err := c.conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("意外关闭错误: %v", err)
			}
			break
		}
	}
}

// 客户端写入协程
func (c *Client) write() {
	defer c.conn.Close()
	for message := range c.send {
		err := c.conn.WriteMessage(websocket.BinaryMessage, message)
		if err != nil {
			log.Println("发送消息失败:", err)
			break
		}
	}
}

// 启动客户端管理器
func (m *ClientManager) start() {
	for {
		select {
		case client := <-m.register:
			m.clients[client] = true
			log.Println("新客户端连接，总数:", len(m.clients))

			// 如果是第一个客户端连接且FFmpeg未运行，启动FFmpeg
			m.mutex.Lock()
			if len(m.clients) == 1 && !m.ffmpegRunning {
				m.mutex.Unlock()
				go startFFmpegProcess()
			} else {
				m.mutex.Unlock()
			}

		case client := <-m.unregister:
			if _, ok := m.clients[client]; ok {
				delete(m.clients, client)
				close(client.send)
				log.Println("客户端断开连接，总数:", len(m.clients))

				// 如果是最后一个客户端断开且FFmpeg正在运行，停止FFmpeg
				m.mutex.Lock()
				if len(m.clients) == 0 && m.ffmpegRunning {
					m.mutex.Unlock()
					m.stopFFmpegProcess()
				} else {
					m.mutex.Unlock()
				}
			}

		case message := <-m.broadcast:
			// 向所有客户端广播消息
			for client := range m.clients {
				select {
				case client.send <- message:
				default:
					close(client.send)
					delete(m.clients, client)
				}
			}
		}
	}
}

// 启动FFmpeg进程
func startFFmpegProcess() {
	manager.mutex.Lock()
	defer manager.mutex.Unlock()

	// 如果已经有FFmpeg进程在运行，不重复启动
	if manager.ffmpegCmd != nil {
		return
	}

	// 获取MP3文件路径（从环境变量或默认值）
	mp3Path := os.Getenv("MP3_PATH")
	if mp3Path == "" {
		mp3Path = "input.mp3" // 默认MP3文件
	}

	// 修改FFmpeg命令，添加循环参数
	cmd := exec.Command("ffmpeg",
		"-re",                // 以本地帧率读取输入
		"-stream_loop", "-1", // 无限循环（-1表示无限）
		"-i", mp3Path, // 输入文件
		"-f", "s16le", // 输出格式：16位有符号整数
		"-acodec", "pcm_s16le", // 音频编码：PCM 16位
		"-ar", "44100", // 采样率：44.1kHz
		"-ac", "2", // 声道数：立体声
		"-") // 输出到标准输出

	// 获取标准输出管道
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Println("获取标准输出管道失败:", err)
		return
	}

	// 启动FFmpeg进程
	if err := cmd.Start(); err != nil {
		log.Println("启动FFmpeg失败:", err)
		return
	}

	manager.ffmpegCmd = cmd
	manager.ffmpegRunning = true
	log.Printf("FFmpeg进程已启动，正在循环播放音频: %s", mp3Path)

	// 异步读取FFmpeg输出并广播
	go func() {
		defer func() {
			manager.mutex.Lock()
			manager.ffmpegCmd = nil
			manager.ffmpegRunning = false
			manager.mutex.Unlock()
		}()

		// 缓冲区大小（4096字节 = 23ms的44.1kHz立体声数据）
		buffer := make([]byte, 4096)

		for {
			n, err := stdout.Read(buffer)
			if n > 0 {
				// 创建音频帧头（简单的长度前缀）
				frame := make([]byte, 4+n)
				binary.BigEndian.PutUint32(frame, uint32(n))
				copy(frame[4:], buffer[:n])

				// 广播到所有客户端
				manager.broadcast <- frame
			}

			if err != nil {
				if err == io.EOF {
					log.Println("读取到文件末尾，但由于循环参数，这应该不会发生")
				} else {
					log.Println("读取FFmpeg输出失败:", err)
				}
				break
			}
		}
	}()
}

// 停止FFmpeg进程
func (m *ClientManager) stopFFmpegProcess() {
	m.mutex.Lock()
	defer m.mutex.Unlock()

	if !m.ffmpegRunning || m.ffmpegCmd == nil {
		return
	}

	log.Println("停止FFmpeg进程...")

	// 尝试优雅地停止FFmpeg进程
	if m.ffmpegCmd.Process != nil {
		// 对于Windows系统，使用Kill而不是Signal
		if runtime.GOOS == "windows" {
			log.Println("Windows系统: 强制终止FFmpeg进程")
			if err := m.ffmpegCmd.Process.Kill(); err != nil {
				log.Println("强制终止失败:", err)
			}
		} else {
			// Unix系统使用Interrupt
			log.Println("Unix系统: 发送中断信号给FFmpeg进程")
			if err := m.ffmpegCmd.Process.Signal(os.Interrupt); err != nil {
				log.Println("无法发送中断信号，尝试强制终止:", err)
				if err := m.ffmpegCmd.Process.Kill(); err != nil {
					log.Println("强制终止失败:", err)
				}
			}
		}
	}

	// 等待进程结束
	if err := m.ffmpegCmd.Wait(); err != nil {
		log.Println("等待FFmpeg进程结束失败:", err)
	}

	m.ffmpegCmd = nil
	m.ffmpegRunning = false
	log.Println("FFmpeg进程已停止")
}

// 手动启动FFmpeg（HTTP接口）
func startFFmpeg(w http.ResponseWriter, r *http.Request) {
	go startFFmpegProcess()
	w.Write([]byte("FFmpeg已启动，正在推送音频..."))
}

// 手动停止FFmpeg（HTTP接口）
func stopFFmpeg(w http.ResponseWriter, r *http.Request) {
	manager.stopFFmpegProcess()
	w.Write([]byte("FFmpeg已停止"))
}
